package com.example.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import android.os.Environment;
import android.util.Log;
/**
 * ��־��¼
 * @author Administrator
 */
public class Loger{

	private LogerImp instance;
	
	//��־���
	private String logerName;
	
	//����ʱ��������Ϊtrue������ʱ��Ҫ����Ϊfalse��
	protected static boolean isOpen = true;
	
	/**
	 * ��ʼ������־��Ϣ<br\>
	 * ��ֻ��Ϊ������־���أ��ڸ��������п���������Ӧ���в��õ��ã�
	 */
	public static void openPrint(){
		if (isOpen){
			LogerImp.instance.startRun();
		}
	}
	
	/**
	 * �ر���־��ӡ <br\>
	 * ��ֻ��Ϊ������־���أ��ڸ��������п���������Ӧ���в��õ��ã�
	 */
	public static void closePrint(){
		if (isOpen){
			LogerImp.instance.stopRun();
		}
	}
	
	private static Loger loger = new Loger("[Loger]");
	
	/**
	 * �����־��Ϣ
	 * @param msg String ��־
	 */
	public synchronized static void print(String msg){
		if (isOpen){
			loger.output(msg);
		}
	}
	
	/**
	 * �����־��Ϣ���쳣�������ϸ��Ϣ
	 * @param msg String ��־
	 * @param e Exception
	 */
	public synchronized static void print(String msg, Exception e){
		if (isOpen){
			loger.output(msg, e);
		}
	}
	
	/**
	 * ���캯��
	 * @param name String
	 */
	public Loger(String name){
		logerName = name;
		instance = LogerImp.getInstance();
	}
	
	/**
	 * �����־��Ϣ
	 * @param msg String ��־
	 */
	public synchronized void output(String msg){
		if (isOpen){
			Log.i(logerName, msg);
			instance.submitMsg(logerName+" "+msg);
		}
	}

	/**
	 * �����־��Ϣ���쳣�������ϸ��Ϣ
	 * @param msg String ��־
	 * @param e Exception
	 */
	public synchronized void output(String msg, Exception e){
		if (isOpen){
			Log.i(logerName, msg, e);
			StringBuffer buf = new StringBuffer(msg);
			buf.append(logerName).append(" : ").append(msg).append("\n");
			buf.append(e.getClass()).append(" : ");
			buf.append(e.getLocalizedMessage());
			buf.append("\n");
			StackTraceElement[] stack = e.getStackTrace();
			for(StackTraceElement trace : stack){
				buf.append("\t at ").append(trace.toString()).append("\n");
			}
			instance.submitMsg(buf.toString());
		}
	}
	
	/**
	 * ��ӡ��ǰ���ڴ���Ϣ
	 */
	public void printCurrentMemory(){
		if (isOpen){
			StringBuilder logs = new StringBuilder();
			long freeMemory = Runtime.getRuntime().freeMemory()/1024;
			long totalMemory = Runtime.getRuntime().totalMemory()/1024;
			long maxMemory = Runtime.getRuntime().maxMemory()/1024;
			logs.append("\t[Memory_free]: ").append(freeMemory).append(" kb");
			logs.append("\t[Memory_total]: ").append(totalMemory).append(" kb");
			logs.append("\t[Memory_max]: ").append(maxMemory).append(" kb");
			Log.i(logerName, logs.toString());
			instance.submitMsg(logerName+" "+logs.toString());
		}
	}
}

/**
 * ��־����ľ���ʵ����
 * @author Administrator
 *
 */
class LogerImp implements Runnable{

	private Loger log = new Loger("[LogerImp]");
	
	static LogerImp instance = new LogerImp();
	
	//��־��ŵĶ���
	private List<String> printOutList = new ArrayList<String>();
	
	//��־�ļ�
	private FileOutputStream fos = null;
	
	//��־�����
	private PrintStream print = null;
	
	//ʱ���ʽ
	private DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

	//�߳���ѯ��ʶ
	private boolean runFlag = false;
	
	//��ǰ�죬ÿ�����һ����־�ļ�
	private int currDay = -1;
	
	private GcCheck gcRun = new GcCheck();
		
	class GcCheck implements Runnable {
		
		boolean flag = true;
		
		@Override
		public void run() {
			int count = 40;
			StringBuffer logs = new StringBuffer();
			while(flag){
				if (count >= 50){
					long freeMemory = Runtime.getRuntime().freeMemory()/1024;
					long totalMemory = Runtime.getRuntime().totalMemory()/1024;
					long maxMemory = Runtime.getRuntime().maxMemory()/1024;
					logs.append("\t[Memory_free]:").append(freeMemory).append(" kb");
					logs.append("\t[Memory_total]:").append(totalMemory).append(" kb");
					logs.append("\t[Memory_max]:").append(maxMemory).append(" kb");
					synchronized (printOutList) {
						printOutList.add(logs.toString());
					}
					Log.i("Memory", logs.toString());
					logs.setLength(0);
					if (freeMemory < 400){
						System.gc();
						count = 40;
						logs.append("<GC>");
					}else{
						count = 0;
					}
				}
				try {
					count++;
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	};
	/**
	 * �õ��������
	 * @return LogerImp
	 */
	public static LogerImp getInstance(){
		return instance;
	}
	
	/**
	 * ˽�з���������
	 */
	private LogerImp(){
	}
	
//	void listenGC(){
//		gcRun.flag = true;
//		new Thread(gcRun).start();
//	}
	
//	void stopLintenGC(){
//		gcRun.flag = false;
//	}
	
	//��ʼ���ļ������
	private void initPrint(){
		Calendar date = Calendar.getInstance();
		currDay = date.get(Calendar.DAY_OF_YEAR);
		DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd");
		String fileName = new String(dfm.format(date.getTime())+".txt");
		String path = null;
		try {
			if (null != print){
				close();
			}
			path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/weiboShare/";
			File dir = new File(path);
			if (!dir.exists()){
				dir.mkdir();
			}
			fos = new FileOutputStream(path+fileName, true);
			print = new PrintStream(fos, true);
		} catch (Exception e) {
			log.output("[LogerImp] δ�ܴ��ļ�:"+path+" �ļ���"+fileName+" �쳣����:"+e.getLocalizedMessage());
		}
	}
	
	/**
	 * �߳̿���
	 */
	public void startRun(){
		if (!runFlag){
			runFlag = true;
			new Thread(this).start();
		}else{
			log.output("[LogerImp] < warn > thread already run !");
		}
	}
	
	/**
	 * �߳�ֹͣ
	 */
	public void stopRun(){
		if (runFlag){
			gcRun.flag = false;
			runFlag = false;
			Log.i("Thread", "���д�С��"+printOutList.size());
			printToFile("[LogerImp] < info > thread stop !");
			close();
		}
	}
	
	private void close() {
		print.flush();
		print.close();
		print = null;
		try{
			fos.close();
			fos = null;
		}catch(IOException e){
			e.printStackTrace();
		}
	}

	/**
	 * �������������־���
	 * @param msg String ��־���
	 */
	protected synchronized void submitMsg(String msg) {
		synchronized (printOutList) {
			printOutList.add(msg);
		}
	}
	
	public void run(){
		try{
			initPrint();
			printToFile("[LogerImp] < info > start new thread ... ");
			while(runFlag){
				runMethod();
			}
			runFlag = false;
		}catch(Exception e){
			printToFile("[LogerImp] < warn > thread error : "+e.getLocalizedMessage());
			if (runFlag){
				printToFile("[LogerImp] �߳�ǿ���ж� "+e.getLocalizedMessage());
				new Thread(this).start();
			}
		}
	}
	
	//�߳���Ҫ�ظ�ִ�еĲ���
	private void runMethod() throws Exception {
		String line = null;
		synchronized (printOutList) {
			if (!printOutList.isEmpty()){
				line = printOutList.remove(0);
			}
		}
		if (null != line){
			printToFile(line);
		}else{
			Thread.sleep(10);
		}
	}
	
	//����ݳ־õ��ļ�
	private void printToFile(String line){
		Calendar date = Calendar.getInstance();
		int day = date.get(Calendar.DAY_OF_YEAR);
		if (day != currDay){
			initPrint();
		}
		if (null == print){
			return;
		}
		print.println(">>> "+format.format(date.getTime())+" -- "+line);
		print.flush();
	}
}